package com.firmiana.jt809.netty;

import com.firmiana.jt809.entity.JT809Message;
import com.firmiana.jt809.util.FunctionUtils;
import com.firmiana.jt809.util.Tools;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 809字节码协议解析转换器，用于nettry server
 *
 * @author linys
 * @create 2018-08-07
 * @since 1.0.0
 */
@Slf4j
public class JT809MessageDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in == null) {
            return;
        }
        in.markReaderIndex();
        while (in.isReadable()) {
            in.markReaderIndex();
            int packetBeginIndex = in.readerIndex();
            byte tag = in.readByte();
            // 搜索包的开始位置，处理黏包和拆包
            if (tag == 0x5B) { //开始
                tag = in.readByte();
                while (tag != 0x5D) {
                    if (!in.isReadable()) {
                        in.resetReaderIndex(); // 没有找到结束包，等待下一次包
                        return;
                    }
                    tag = in.readByte();
                }
                int pos = in.readerIndex();
                int packetLength = pos - packetBeginIndex;

                if (packetLength > 1) {
                    byte[] tmp = new byte[packetLength];
                    in.resetReaderIndex();
                    in.readBytes(tmp);//重读


                    String content = Tools.toHexString(tmp).toUpperCase();
                    String totalMsgPacket = content;
                    String headFlag = content.substring(0, 2);
                    content = FunctionUtils.decoderStringEscape(tmp);
                    String strLength = content.substring(2, 10);
                    int len = Integer.valueOf(strLength, 16);
                    content = content.substring(10, content.length());
                    long msgSn = Long.valueOf(content.substring(0, 8), 16);
                    int msgId = Integer.valueOf(content.substring(8, 12), 16);
                    long msgGpsCenterId = Long.valueOf(content.substring(12, 20), 16);
                    int encryptFlag = Integer.valueOf(content.substring(26, 28), 16);
                    long encryptKey = Long.parseLong(content.substring(28, 36), 16);
                    String msgBody = "";
                    if ((len > 16) && (content.length() > 42)) {
                        // FIXME 这段处理有疑问
                        msgBody = content.substring(36, len * 2 - 16);
                    } else {
                        msgBody = "";
                    }
                    String endFlag = content.substring(content.length() - 2, content.length());
                    if (endFlag.equalsIgnoreCase("5D")) {
                        JT809Message mm = new JT809Message(msgId);
                        mm.setHeadFlag(headFlag);
                        mm.setMsgLength(len);
                        mm.setMsgType(msgId);
                        mm.setMsgGNSSCenterID(msgGpsCenterId);
                        mm.setMsgSN(msgSn);
                        if ((encryptFlag == 1) && (msgBody.length() > 0)) {
                            msgBody = FunctionUtils.encrypt(encryptKey, msgBody);
                            //logger.info("key" + encryptFlag);
                        }

                        mm.setPacketDesc(totalMsgPacket);
                        mm.setMessageBody(msgBody);
                        mm.setEndFlag(headFlag);
                        mm.setEncryptFlag((byte) encryptFlag);
                        mm.setEncryptKey(encryptKey);
                        out.add(mm);
                    }
                } else {
                    // 说明是0x5B0x5D
                    in.resetReaderIndex();
                    in.readByte(); // 0x5B0x5D说明前面是包尾，后面是包头
                }
            }
        }
        // FIXME mock data
        JT809Message mm = new JT809Message(26);
        mm.setMsgGNSSCenterID(0x10);
        mm.setMessageBody("1234abcd127.0.0.17777");
        mm.setMsgType(0x1001);
        out.add(mm);

    }
}
